﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Scribd.Net
{
	/// <summary>
	/// A helper class for managing a local store of 
	/// files that have been sent to Scribd.
	/// </summary>
	public sealed class ScribdDb
	{
		private static ScribdDb m_instance;
		private List<Row> m_rows;

		/// <summary>
		/// ctor - required for serialization
		/// </summary>
		internal ScribdDb() { m_rows = new List<Row>(); }

		/// <summary>
		/// Internal instance
		/// </summary>
		internal static ScribdDb Instance
		{
			get
			{
				if (m_instance == null)
				{
					m_instance = new ScribdDb();
				} return m_instance;
			}
		}

		/// <summary>
		/// Saves to the local DbPath
		/// </summary>
		internal static void Save()
		{
			if (!string.IsNullOrEmpty(DbPath))
			{
				XmlSerializer _serializer = new XmlSerializer(typeof(ScribdDb));
				using (Stream _stream = new FileStream(DbPath, FileMode.Create))
				{
					XmlWriter _xmlWriter = new XmlTextWriter(_stream, Encoding.UTF8);
					_serializer.Serialize(_xmlWriter, ScribdDb.Instance);
				}
			}
		}

		/// <summary>
		/// Loads from the local DbPath
		/// </summary>
		internal static void Load()
		{
			if (!string.IsNullOrEmpty(DbPath) && File.Exists(DbPath))
			{
				XmlSerializer _serializer = new XmlSerializer(typeof(ScribdDb));
				using (Stream _stream = new FileStream(DbPath, FileMode.Open))
				{
					XmlReader _xmlReader = new XmlTextReader(_stream);
					ScribdDb _temp = (ScribdDb)_serializer.Deserialize(_xmlReader);
					ScribdDb.Instance.Database.AddRange(_temp.Database);
				}
			}
		}

		/// <summary>
		/// Full path and filename to the local store
		/// </summary>
		[XmlIgnore()]
		public static string DbPath { get; set; }

		/// <summary>
		/// Elements in the local store
		/// </summary>
		[XmlElement("Row")]
		public List<Row> Database
		{
			get
			{
				if (m_rows == null)
				{
					m_rows = new List<Row>();
					ScribdDb.Load();
				}
				return m_rows;
			}
			set
			{
				m_rows = value;
			}
		}

		/// <summary>
		/// Add an entry to the local store.
		/// </summary>
		/// <param name="fileName">Local path to the file</param>
		/// <param name="document">Scribd Document to store</param>
		public static void Add(string fileName, Document document)
		{
			if (!ScribdDb.Instance.Database.Exists(delegate(Row _row) { return (_row.DocumentId == document.DocumentId); }))
			{
				Row _row = new Row();
				_row.Created = DateTime.Now;
				_row.DocumentId = document.DocumentId;
				_row.Document = document;
				_row.FileName = fileName;
				ScribdDb.Instance.Database.Add(_row);
				ScribdDb.Save();
			}
		}

		/// <summary>
		/// Pulls the Document information from the local store.
		/// </summary>
		/// <param name="fileName">Local path to the file</param>
		/// <returns><see cref="T:Scribd.Net.Document"/></returns>
		public static Document FindDocument(string fileName)
		{
			Row _result = ScribdDb.Instance.Database.Find(delegate(Row _row) { return (_row.FileName == fileName); });
			return _result.Document;
		}

		/// <summary>
		/// Remove an entry from the local store.
		/// </summary>
		/// <param name="documentId">Scribd-assigned document id</param>
		public static void Remove(int documentId)
		{
			ScribdDb.Instance.Database.RemoveAll(delegate(Row _row) { return (_row.DocumentId == documentId); });
			ScribdDb.Save();
		}

		/// <summary>
		/// Removes an entry from the local store.
		/// </summary>
		/// <param name="fileName">Local path to the file</param>
		public static void Remove(string fileName)
		{
			ScribdDb.Instance.Database.RemoveAll(delegate(Row _row) { return (_row.FileName == fileName); });
			ScribdDb.Save();
		}

		/// <summary>
		/// An entry in the local store
		/// </summary>
		public class Row
		{
			/// <summary>
			/// ctor
			/// </summary>
			public Row() { }

			/// <summary>
			/// Local filename
			/// </summary>
			[XmlElement()]
			public string FileName { get; set; }

			/// <summary>
			/// The document identifier
			/// </summary>
			[XmlAttribute()]
			public int DocumentId { get; set; }

			/// <summary>
			/// Date entry was created
			/// </summary>
			[XmlAttribute()]
			public DateTime Created { get; set; }

			/// <summary>
			/// Document stored
			/// </summary>
			[XmlElement()]
			public Document Document { get; set; }
		}

	}
}